// @Description
// @Author  xiaoyang
// @Date  2022/2/22 10:58 上午

package codec

import (
	"bufio"
	"encoding/gob"
	"io"
	"log"
)

type GobCodec struct {
	conn io.ReadWriteCloser // 连接实例：通过 TCP 或者 Unix 建立 socket 时得到的链接实例
	buf  *bufio.Writer      // buf 是为了防止阻塞而创建的带缓冲的 Writer
	dec  *gob.Decoder
	enc  *gob.Encoder
}

// Close
/**
 *  @Author yang
 *  @Description 关闭流
**/
func (g *GobCodec) Close() error {
	return g.conn.Close()
}

// ReadHeader
/**
 *  @Author yang
 *  @Description 头部读取
**/
func (g *GobCodec) ReadHeader(header *Header) error {
	return g.dec.Decode(header)
}

// ReadBody
/**
 *  @Author yang
 *  @Description 消息体读取
**/
func (g *GobCodec) ReadBody(body interface{}) error {
	return g.dec.Decode(body)
}

func (g *GobCodec) Write(header *Header, body interface{}) (err error) {
	defer func() {
		_ = g.buf.Flush()
		if err != nil {
			_ = g.conn.Close()
		}
	}()

	if err := g.enc.Encode(header); err != nil {
		log.Println("rpc codec: gob error encoding header:", err)
		return err
	}

	if err := g.enc.Encode(body); err != nil {
		log.Println("rpc code: gob error encoding body:", err)
		return err
	}

	return nil
}

var (
	// 初始化变量 Codec
	_ Codec = (*GobCodec)(nil)
)

// NewGobCodec
/**
 *  @Author yang
 *  @Description 创建编码结构体
**/
func NewGobCodec(conn io.ReadWriteCloser) Codec {
	buf := bufio.NewWriter(conn)
	return &GobCodec{
		buf:  buf,
		conn: conn,
		dec:  gob.NewDecoder(conn),
		enc:  gob.NewEncoder(buf),
	}
}
